package core

import (
	"time"
	"zinx_websokect_poker/zinx_app/poker_game/card"
	"zinx_websokect_poker/zinx_app/poker_game/log"
	"zinx_websokect_poker/zinx_app/poker_game/model"
	"zinx_websokect_poker/zinx_app/poker_game/protocol"
	"zinx_websokect_poker/zinx_app/poker_game/util"
)

const (
	RUNNING  uint8 = 1
	GAMEOVER uint8 = 0
	BEGIN    uint8 = 1
	READY    uint8 = 0
)

const (
	SetDepend  int = iota // 定庄
	Round1 // 下注一
	Round2 // 下注二
	Round3 // 下注三
	Round4 // 下注四
	Result // 游戏结果
	NoGame // 当前没有游戏进行
)

//玩家投注动作
const (
	GiveUp = iota // 弃牌
	Bet    = 1 // 下注
	Check  = 2 // 让牌
	Follow = 3 // 跟注
	AddBet = 4 // 加注
	AllIn  = 5 // All In
)

//筹码动画展示效果
const (
	noMine = iota //
	NoShow
	ShowChip
	AddShowChip
)

type Room struct {
	*model.Room
	Occupants   []*Occupant
	staticOccupants []Occupant //静态数据，用来保存玩家离开座位的数据
	winners     []*Occupant
	observes    []*Occupant // 站起的玩家
	AutoSitdown []*Occupant // 自动坐下队列

	//游戏阶段管道
	//reqRound2 chan int
	//reqRound3 chan int
	//reqRound4 chan int
	//reqResult chan int
	//waitAction bool
	StartAble bool           // 游戏可开始的标识，默认为true，房间倒计时后设为false。
	remain int
	allin  int
	isAllin  bool			 // 当游戏玩家都Allin的时候置为true
	n      uint8
	status uint8
	GameState int
	SB       uint32          // 小盲注
	sbPos    uint8
	bbPos    uint8
	BB       uint32          // 大盲注
	Mult     int         // 大盲注倍数
	Cards    card.TCards // 公共牌
	Pot      []uint32        // 奖池筹码数, 第一项为主池，其他项(若存在)为边池
	Timeout  time.Duration   // 倒计时超时时间(秒)
	Button   uint8           // 当前庄家座位号，从1开始
	Current  uint8           // 当前下注玩家的座位号
	Chips    []uint32        // 玩家本局下注的总筹码数，与occupants一一对应
	Bet      uint32          // 当前回合 上一加注玩家下注额
	BetPos   uint8          // 当前回合 上一加注的玩家
	BetPrePos   uint8          // 当前回合 第一个下注玩家的上一位玩家座位号
	CurrentChip uint32       // 当前回合,最大的注

	PreBet   uint32			// 记录上一个玩家的操作
	Max      uint8           // 房间最大玩家人数
	RoomTime uint32			 // 房间结束时间（分钟）xx分钟后关闭房间
	MaxChips uint32
	MinChips uint32
	IsBegin  uint8			//是否开始过游戏
	OwnerOc  *Occupant			//内部生成的玩家对应的id
	ServiceCharge      uint8            //抽水比例

	order int // 每回合的动作顺序
	betFlag bool // 每回合首先下注的标志
	UserAction protocol.UserAction // 每回合最后一饿下注的人的动作
	SecondsTimer *util.SecondsTimer //下注倒计时的定时器
	RoomSecondsTimer *util.SecondsTimer //创建房间的定时器
}

// NewRoom 新建房间
func NewRoom(max uint8, sb, bb uint32, chips uint32, timeout uint32, owner int64,oc *Occupant) *Room {
	if max <= 0 || max > 9 {
		max = 9 // default 9 Occupants
	}
	//timeout = 1
	r := &Room{
		Room:      &model.Room{DraginChips: chips, Owner: owner, CreatedAt: time.Now()},
		//MsgLoop:   room.NewMsgLoop(),
		Chips:     make([]uint32, max),
		Occupants: make([]*Occupant, max),
		staticOccupants: make([]Occupant, max),
		Pot:       make([]uint32, 0, max),
		Timeout:   time.Second * time.Duration(model.Timeout),
		SB:        sb,
		BB:        bb,
		Max:       max,
		RoomTime:  timeout,
		OwnerOc:   oc,
		ServiceCharge: 5,
		StartAble: true,
	}
	//房间设置定时器
	r.RoomSecondsTimer = util.NewSecondsTimer(time.Duration(timeout) * time.Minute)
	go func() {
		// 协程，时间到判断房间状态，关闭房间。
		select {
		case <-r.RoomSecondsTimer.Timer.C:
			r.RoomSecondsTimer.Timer.Stop()
			r.StartAble = false
			if !r.IsRunning(){
				//不在游戏中：清理房间中的玩家，关闭房间。
				log.Info("Room-TimeOut", "【解散房间】房间超时，房间号：" + r.Number)
				r.ClearRoom()
			}
		}
	}()

	return r
}

type StartDelay struct {
	kind uint8
}

//调用玩家类的WriteMsg
func (r *Room) WriteMsg(msg interface{}, exc ...uint32) {
	for _, v := range r.Occupants {
		if v != nil {
			for _, uid := range exc {
				if uid == v.GetPlayerid() {
					goto End
				}
			}
			v.WriteMsg(msg)
		}
	End:
	}
}

//广播消息
func (r *Room) Broadcast(msg interface{}, all bool, exc ...uint32) {
	for _, v := range r.Occupants {
		//all 给所有人
		if v != nil && (all || !v.IsGameing()) {
			for _, pid := range exc {
				//用户Pid
				if pid == v.GetPlayerid() {
					goto End1
				}
			}
			v.WriteMsg(msg)
		}
	End1:
	}
	for _, v := range r.observes {
		if v != nil {
			for _, uid := range exc {
				if uid == v.Pid {
					goto End
				}
			}
			v.WriteMsg(msg)
		}
	End:
	}
}

//添加玩家进房间
func (r *Room) addOccupant(o *Occupant) uint8 {
	//查找玩家是否已在房间内
	for _, v := range r.Occupants {
		if v != nil && v.GetPlayerid() == o.Pid {
			return 0
		}
	}

	for k, v := range r.Occupants {
		if v == nil {
			r.Occupants[k] = o
			o.SetRoom(r)
			o.Pos = uint8(k + 1)
			o.SetSitdown()
			return o.Pos
		}
	}
	return 0
}

//从房间中移除玩家
func (r *Room) removeOccupant(o *Occupant) uint8 {
	if o != nil {
		r.Occupants[o.Pos-1] = nil
		//r.Occupants[o.Pos-1].isStandUp = true
		return o.Pos
	}
	return 0
}

//添加玩家进房间旁观
func (r *Room) addObserve(o *Occupant) uint8 {
	for _, v := range r.observes {
		if v != nil && v.Pid == o.Pid {
			return 0
		}
	}
	o.SetObserve()
	r.observes = append(r.observes, o)
	return 0
}

//从旁观者中移除
func (r *Room) removeObserve(o *Occupant) {
	for k, v := range r.observes {
		if v != nil && v.Pid == o.Pid {
			//r.observes = append(r.observes[:k], r.observes[k+1:]...)
			r.observes[k] = nil
			return
		}
	}
}

// start starts from 0
func (r *Room) Each(start uint8, f func(o *Occupant) bool) {
	volume := r.Cap()
	end := (volume + start - 1) % volume
	i := start
	//调用Each，return true继续循环直到结束，return false则是跳出循环。
	for ; i != end; i = (i + 1) % volume {
		if r.Occupants[i] != nil && r.Occupants[i].IsGameing() && !f(r.Occupants[i])   {
			return
		}
	}

	// end
	if r.Occupants[i] != nil && r.Occupants[i].IsGameing() {
		f(r.Occupants[i])
	}
}

func (r *Room) Cap() uint8 {
	return r.Max
}

func (r *Room) Len() uint8 {
	var num uint8
	for _, v := range r.Occupants {
		if v != nil {
			num ++
		}
	}
	return num
}

func (r *Room) ObLen() uint8 {
	var num uint8
	for _, v := range r.observes {
		if v != nil {
			num ++
		}
	}
	return num
}

func (r *Room) GetNumber() string {
	return r.Number
}
func (r *Room) SetNumber(value string) {
	r.Number = value
}

func (r *Room) Data() interface{} {
	return r.Room
}

func (r *Room) SetData(d interface{}) {
	r.Room = d.(*model.Room)
}

func (r *Room) GetAllPid() []uint32 {
	var b []uint32
	for _, occupant := range r.Occupants {
		if occupant != nil && occupant.IsGameing() {
			b = append(b, occupant.GetPlayerid())
		}
	}
	return b
}

func (r *Room) IsRunning() bool {
	return r.status == RUNNING
}

func (r *Room) IsBeginning() bool {
	return r.IsBegin == BEGIN
}

func (r *Room) SetSecondsTimer(timer *util.SecondsTimer) {
	r.SecondsTimer = timer
}

func (r *Room) ClearRoom(){
	//清理座位上的玩家
	if r.Len() > 0 {
		for i, oc := range r.Occupants {
			if oc != nil {
				//调用离开房间
				r.LeaveRoom(r.Occupants[i])
			}
		}
	}
	//清理旁观者
	if r.ObLen() > 0 {
		for i, ob := range r.observes {
			if ob != nil {
				//调用离开房间
				r.LeaveRoom(r.observes[i])
			}
		}
	}
}